【レポート】コンテナイメージとはなにかを徹底的にDeepDive!SOCIについて学べるワークショップに参加してきました #AWSreInvent #SVS402

【レポート】コンテナイメージとはなにかを徹底的にDeepDive!SOCIについて学べるワークショップに参加してきました #AWSreInvent #SVS402

コンテナイメージとはなにかを徹底的に学べるセッションです!個人的にめちゃくちゃ良いセッションでした!
Clock Icon2024.12.05

お疲れさまです。とーちです。re:Invent2024に参加してます。
この記事では「 SVS402 | Lazy loading container images with Seekable OCI (SOCI) 」のセッションレポートをお届けします。

セッションの概要

タイトル

SVS402 | Lazy loading container images with Seekable OCI (SOCI)

概要

Seekable OCI (SOCI) is an open source AWS technology that enables containers to launch faster by lazily loading the container image. In this workshop, get hands-on with SOCI. Learn how to create SOCI indexes for existing container images and how index generation can be automated in the cloud. Then, practice deploying workloads to Amazon ECS with AWS Fargate, considering how launch times are reduced by lazily loading container images. You must bring your laptop to participate.

※日本語訳
Seekable OCI (SOCI) は、コンテナイメージの遅延読み込みによりコンテナの起動を高速化するオープンソースのAWSテクノロジーです。このワークショップでは、SOCIを実際に体験します。既存のコンテナイメージに対するSOCIインデックスの作成方法と、インデックス生成のクラウドでの自動化方法を学びます。次に、コンテナイメージの遅延読み込みによる起動時間の短縮を考慮しながら、AWS Fargateを使用したAmazon ECSへのワークロードのデプロイを実践します。参加するには、ノートパソコンを持参する必要があります。

スピーカー

Phil Estes, Principal Engineer, AWS
Olly Pomeroy, Specialist Solution Architect, Containers, Amazon Web Services

セッションタイプ

Workshop

概要

SOCI(Seekable OCI)を学ぶためにコンテナイメージの実体とはそもそもどういったものなのかを深堀りし、SOCIと通常のコンテナイメージとの違いやSOCIインデックスの作り方、ECRへのpushの仕方、また通常のコンテナイメージとどのくらいスピードに差があるのかといったところまで体験するセッションでした。

ワークショップの流れ

ワークショップの流れとしては以下のような形です。

  1. コンテナイメージとはなにかをDeepDiveする
  2. SOCI CLIでSOCIインデックスを生成する
  3. SOCIインデックスビルダーを使いSOCIインデックスを生成する
  4. Amazon ECS(以下ECS)Fargateでコンテナイメージの遅延読み込みをやってみる
  5. ECSタスクでSOCIインデックスの使用有無によりどの程度の差がでるかを確認する

実際のワークショップで体験したこと

実際のワークショップで行ったことを印象深かったポイントを中心にお届けします。

コンテナイメージとはなにかをDeepDiveする

SOCIはコンテナイメージのレイヤーの仕組みと密接に関わるので、まずはコンテナイメージとはなにかを理解しよう、というところから始まりました。
この項目ではコマンドを使いつつコンテナイメージのかなり細かいところまでを知ることが出来る内容になっており、とても勉強になりました。復習もかねてこの記事で出来る限りお伝えしようと思います。

コンテナイメージの内部構造

コンテナイメージを理解しやすくするために、amazonlinux2023のベースイメージにnginxをインストールしたDockerfileを使って進めていきました。
Dockerfileは以下のような内容です。

FROM public.ecr.aws/amazonlinux/amazonlinux:2023-minimal

RUN dnf install -y nginx

COPY index.html /usr/share/nginx/html/index.html

CMD ["nginx", "-g", "daemon off; error_log /dev/stdout info;"]

このDockerfileをビルドするのですが、ビルドにfinchを使っていました。私は初めて使ったのですが、かなりdockerコマンドライクに使えるんですね。例えばビルドは以下のコマンドでした。

finch build --tag nginx-demo .

まず、finch image inspect コマンドでコンテナイメージの詳細を見ます。出力結果の中にイメージのレイヤー情報が含まれています。

        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:628e1e71d54a534c27a15d57d228fd692284434973429550643615d7547785cb",
                "sha256:a99c6640830bff93f9029b80f92f67a528e925072f50884d84d32ab69905075a",
                "sha256:4a423038deabae8732f3ebf59f382e133539eeca3008df808cdd9cb1610645e4"
            ]
        },

レイヤーとは個々のファイルシステムであり、UnionFSによってコンテナ起動時にまとめられるということでした。
UnionFSを知らなかったので、少し調べてみたところ、以下のサイトの例がわかりやすかったです。

まとめて束ねるUnionFSの不思議な世界 | TECHSCORE BLOG

別々のディレクトリにあるファイルを一つのディレクトリにまとめるといった動きをするようです。

上記のDockerfileは以下のように3つのレイヤーが積み重なっているようなイメージになるとのこと

image.png

また、finch image inspect コマンドで表示された各レイヤーの sha256 から始まる値ですが、これは各レイヤーのファイルシステム全体のSHA256ハッシュ値とのことでした。これも知らなかったことです。(そもそも意識したことがなかった。。)

続いてビルドしたDockerイメージをECRにpushします。push後に aws ecr list-images コマンドを実行すると以下のようにECR上コンテナイメージのimageDigestを取得することができます。

$ aws ecr list-images --repository-name nginx-demo
{
    "imageIds": [
        {
            "imageDigest": "sha256:e55ec1cc522ed443723b483bbaecb51b750e612bb97eeb31b3906092afdb82d7",
            "imageTag": "latest"
        }
    ]
}

このimageDigestは何らかの値をSHA256ハッシュ化したものなわけですが、何をハッシュ化したものなのでしょうか?それもちゃんとワークショップの中で説明がありました。
ハッシュ化されているのはイメージマニフェストというコンテナのメタデータファイルになります。

コンテナイメージをECRにpushしたとき、実際には3つのレイヤーと2つのメタデータファイルをアップロードしているそうです。そのうちの一つがイメージマニフェストになります。以下のイメージです。

image.png

イメージマニフェストとは何なのでしょうか?実は aws ecr batch-get-image コマンドでECR上のイメージマニフェストを取得することができます。
取得したマニフェストファイルは以下のようなものになっています。

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
  "config": {
    "mediaType": "application/vnd.docker.container.image.v1+json",
    "digest": "sha256:1d09f59dd311c8f61fcf4784efb856d0e30ad5d8f3a2a1b10539efe6d6ecfedf",
    "size": 1322
  },
  "layers": [
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "digest": "sha256:808624112091b2c7033d4058144489bdca4c01777436e89b4d8d4a197f2dd9c1",
      "size": 34236251
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "digest": "sha256:0bd62ec97db90bde06777498677f3ee17a293206dcefb79931743df997e8aeea",
      "size": 77316296
    },
    {
      "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
      "digest": "sha256:60347bdb18d2a8fa73376605b701acc86408e861eebe45bfd13c69f8af6c6510",
      "size": 623
    }
  ]
}

マニフェストファイルにはコンテナイメージの構成情報であるレイヤーの情報やmediaTypeというマニフェストファイルがどの形式であるのかを示す情報が含まれています。上の例でいうと application/vnd.docker.distribution.manifest.v2+json と書かれており、これは Docker Manifest v2コンテナイメージ仕様になるようです。

上記のマニフェストファイルをハッシュ化したものが、イメージダイジェストになるとのことでした。ワークショップではローカル上にあるコンテナイメージからマニフェストファイルを取り出しそのハッシュ値と aws ecr list-images の結果を比較するといったこともやりました。

また、重要な点として、ECRは各コンテナイメージのレイヤーをS3に保存しているそうです。そうだったのか、、という感じです。
ワークショップでは実際に aws ecr get-download-url-for-layer というコマンドを使用して、S3URLを取得し、レイヤーをダウンロードしてくるといったことまでやっていました。深すぎる。。

このレイヤーの中身というのがとても興味深かったので、共有します。 ダウンロードしてきたレイヤーはtar.gzで圧縮されています。このファイルを展開すると中身は以下のようになっていました。

.
└── usr
    └── share
        └── nginx
            └── html
                └── index.html

これがどこのレイヤーのファイルかわかりますでしょうか?そうです。以下の行のレイヤーになります。なるほどといった感じですよね。

COPY index.html /usr/share/nginx/html/index.html

この「ECRは各コンテナイメージのレイヤーをS3に保存している」という仕組みがSOCIに関係してきます。

SOCI CLIでSOCIインデックスを生成する

従来、ECSタスクが起動(コンテナイメージをpull)すると全てのコンテナイメージレイヤーがダウンロードされていました。SOCIという仕組みを用いることで「遅延読み込み」が可能になります。遅延読み込みでは、全てのレイヤーをダウンロードするのではなく、イメージマニフェストとSOCI Indexというコンテナイメージ内のすべてのファイルのインデックスのようなものを最初にダウンロードするそうです。

image.png

SOCI Indexは通常のdocker build(このワークショップではfinch build)ではDockerイメージに含まれないので専用のコマンドでビルドをする必要があります。
そのコマンドが、 SOCI CLI になります。ここではSOCI CLIを使ったSOCIインデックスの作成方法を学びました。

ちなみにSOCIには2つの主要なコンポーネントがあります。

  • soci-snapshotter:サーバー側で実行され、コンテナ イメージの遅延読み込みを処理するランタイム コンポーネント。
  • SOCI CLI:ローカル マシン上で SOCI インデックスを作成するためのクライアント側CLI

以下のコマンドを実行することでSOCIインデックスを作成できました。なおワークショップ環境には最初からsociコマンドが入っていました。

soci create $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/nginx-demo:latest

上記のコマンドを実行することで、zTOCと呼ばれる全てのファイルのインデックスを作成します。
ワークショップではさらにSOCIインデックスの中身も確認しました。SOCIインデックスの内容はイメージマニフェストと似ていますが、異なる点として、subjectというフィールドがあり、ここにはこのSOCIインデックスがどのコンテナイメージに紐づけられているかが記載されていました。ちなみにSOCIインデックスはOCI準拠レジストリ(ECR等)にコンテナイメージとは別にアップロードされます。(そのため紐づけの定義が必要と思われる)

# SOCIインデックスの一部
  "subject": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:e55ec1cc522ed443723b483bbaecb51b750e612bb97eeb31b3906092afdb82d7",
    "size": 897
  },

SOCIインデックスとzTOCがごっちゃになりそう(私はなった)ですが、わかりやすい絵があったのでこちらも載せておきます。

image.png

SOCIインデックスビルダーを使いSOCIインデックスを生成する

上記のsociコマンドですが、各開発端末にいれるのが面倒そうだと思いませんか?
そんな方のためにSOCIインデックスビルダーというソリューションが提供されています。

これを使うとコンテナイメージがECRにプッシュされたときにSOCIインデックスを自動で生成してくれるとのことです。

アーキテクチャはこんな感じ

image.png

CFN AWS SOCI Index Builder on AWS より参照

デプロイはCFnから実行できます。

Amazon ECS Fargateでコンテナイメージの遅延読み込みをやってみる

このセクションでは実際にECS FargateでSOCIを使った遅延読み込みを実施しました。
ECRにSOCIインデックスと紐づくコンテナイメージがpushされていれば、ECSタスク定義やECSサービス定義に特別な設定はいらないようです。(Fargateはデフォルトで全てのコンテナイメージを遅延読み込みしようとすると書いてありました)

遅延読み込みがちゃんとされたかどうかを確認するには通常の手段ではecs execでコンテナの中に入って、複雑なコマンドを実行して確認するしかないようです。
代替の確認手段として、am-i-lazyというサイドカーコンテナが紹介されていました。このコンテナを使うとCloudWatchLogsに遅延読み込みされたかどうかをログとして送信してくれるので、こういったものを使うのも一つの手かと思います。

ECSタスクでSOCIインデックスの使用有無によりどの程度の差がでるかを確認する

最後に遅延読み込みでどのくらいの差が出るかを確認しました。実際に試した際には遅延読み込みのほうが、起動開始が29秒だったのに対し、通常のものが86秒とだいぶ遅延読み込みのほうが早かったです。

しかしここで注意点があります。遅延読み込みは250 MB以上のコンテナイメージでないと効果は薄いということです。特に機械学習やデータ処理などコンテナイメージが大きくなるワークロードで効果を発揮するとのことでした。

まとめ

SOCI(Seekable OCI)を学ぶためにコンテナイメージの実体とはそもそもどういったものなのかを深堀りし、かなり具体的なところまで体験できるセッションになっており、私としてはとても学びになることが多いセッションでした。こういう深いところまでやるセッションって本当にいいですね。

以上、とーちでした。

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.